import collections
from os import path

from wechatpy import WeChatPay

from app import settings

PEM_BASE_DIR = path.join(settings.BASE_DIR, *['app', 'pem', 'wx'])
MCH_CERT_PATH = path.join(PEM_BASE_DIR, 'apiclient_cert.pem')
MCH_KEY_PATH = path.join(PEM_BASE_DIR, 'apiclient_key.pem')
WX_APP_ID = 'wxe9b6e3273506cfbd'
MCH_API_KEY = 'xinzishangchengPG039683xinziscsc'
MCH_ID = '1613424585'


def get_wx_pay(sandbox=False):
    try:
        return WeChatPay(
            appid=WX_APP_ID,
            api_key=MCH_API_KEY,
            mch_id=MCH_ID,
            mch_cert=MCH_CERT_PATH,
            mch_key=MCH_KEY_PATH,
            timeout=30,
            sandbox=sandbox
        )
    except Exception as e:
        print('初始化微信支付异常', e)
        return None


class WxPay:
    wxPay = None

    def __init__(self, sandbox=False):
        self.wxPay = get_wx_pay(sandbox)

    """
        ('return_code', 'SUCCESS'), 
        ('return_msg', 'OK'), 
        ('result_code', 'SUCCESS'), 
        ('mch_id', '1613424585'), 
        ('appid', 'wxe9b6e3273506cfbd'),
        ('nonce_str', 'RrrkKh0E6mZM3p2G'), 
        ('sign', '666B7569E338704C8E139B0FE9D0D0BC'), 
        ('openid', 'oRgod5pvw7PDJAz6EwbBNSGT6HB8'), 
        ('is_subscribe', 'N'),
        ('trade_type', 'MICROPAY'),
        ('bank_type', 'CMB_DEBIT'), 
        ('fee_type', 'CNY'), 
        ('total_fee', '15'),
        ('cash_fee_type', 'CNY'), 
        ('cash_fee', '15'), 
        ('transaction_id', '4200001132202110149706366282'), 
        ('out_trade_no', '1613424585202110141657105672'), 
        ('attach', None), 
        ('time_end', '20211014165711')
    """

    # http://docs.wechatpy.org/zh_CN/stable/pay.html#wechatpy.pay.WeChatPay.micropay
    def barcodePay(self, auth_code, out_trade_no, fen, desc='', opt=None):
        if opt is None:
            opt = {}
        trade_no = ''
        tp_resp = None
        result_code = 'FAIL'
        try:
            opt.update({'out_trade_no': out_trade_no})
            tp_resp = self.wxPay.micropay.create(desc, fen, auth_code, **opt)
            if type(tp_resp) is collections.OrderedDict:
                return_code = tp_resp.get('return_code', '')
                result_code = tp_resp.get('result_code', '')
                trade_type = tp_resp.get('trade_type', '')
                if return_code == 'SUCCESS' and result_code == 'SUCCESS' and trade_type == 'MICROPAY':
                    trade_no = tp_resp.get('transaction_id', '')
                    return result_code, trade_no, tp_resp, None
                else:
                    return result_code, trade_no, tp_resp, tp_resp.get('err_code_des', '支付失败')
            else:
                return result_code, trade_no, tp_resp, '响应格式错误'
        except Exception as e:
            err = '支付异常'
            print(err, e.args)
            if type(e.args) is tuple and len(e.args) == 5:
                err_code = e.args[3]
                err = e.args[4]
                if err_code == 'USERPAYING':
                    result_code = ''
                tp_resp = {
                    'trade_state': err_code,
                    'trade_state_desc': err
                }
        return result_code, trade_no, tp_resp, err

    """
    {
        "return_code":"SUCCESS",
        "return_msg":"OK",
        "appid":"wxe9b6e3273506cfbd",
        "mch_id":"1613424585",
        "nonce_str":"eZsMrmY7soeTCzxh",
        "sign":"3C515B2CB2FA0472364C7CC2FCA31871",
        "result_code":"SUCCESS",
        "transaction_id":"4200001219202110214456103196",
        "out_trade_no":"2110211401257937417NZKI",
        "out_refund_no":"tuitest001",
        "refund_id":"50301110072021102113574691033",
        "refund_channel":null,
        "refund_fee":"1289",
        "coupon_refund_fee":"0",
        "total_fee":"1290",
        "cash_fee":"1290",
        "coupon_refund_count":"0",
        "cash_refund_fee":"1289"
    }
    """

    def refund(self, total_fee,
               refund_fee,
               out_trade_no,
               refund_desc='',
               out_refund_no=None,
               transaction_id=None,
               opt=None):
        if opt is None:
            opt = {}
        tp_resp = {}
        refund_id = ''
        try:
            if transaction_id is not None:
                opt.update({'transaction_id': transaction_id})
            if refund_desc != '':
                opt.update({'refund_desc': refund_desc})
            if out_refund_no is None:
                out_refund_no = out_trade_no + 'R'
            opt.update({'out_trade_no': out_trade_no})
            tp_resp = self.wxPay.refund.apply(total_fee, refund_fee, out_refund_no, **opt)

            if type(tp_resp) is collections.OrderedDict:
                if tp_resp.get('return_code', '') == 'SUCCESS':
                    refund_id = tp_resp.get('refund_id', '')
                    return refund_id, tp_resp, None
                else:
                    return refund_id, tp_resp, tp_resp.get('err_code_des', '退款失败')
            else:
                return refund_id, tp_resp, '响应格式错误'
        except Exception as e:
            err = '退款异常'
            if type(e.args) is tuple and len(e.args) == 5:
                err = e.args[4]
        return refund_id, tp_resp, err

    def queryOrder(self, out_trade_no=None, trade_no=None):
        err = None
        res = {}
        traded_no = ''
        trade_state = ''
        try:
            tp_res = self.wxPay.micropay.query(transaction_id=trade_no, out_trade_no=out_trade_no)
            trade_state = tp_res.get('trade_state', '')
            traded_no = tp_res.get('transaction_id', '')
            for key in tp_res:
                res.update({key: tp_res.get(key)})
        except Exception as e:
            err = '支付订单查询异常'
            if len(e.args) == 5:
                err = e.args[4]
        if trade_state == 'USERPAYING':
            err = '支付中...'
        return traded_no, trade_state, res, err
